package com.zheng.redpacket.server.serivce.Impl;

import com.zheng.redpacket.mdg.mapper.BookRobMapper;
import com.zheng.redpacket.mdg.mapper.BookStockMapper;
import com.zheng.redpacket.mdg.model.BookRob;
import com.zheng.redpacket.mdg.model.BookStock;
import com.zheng.redpacket.server.dto.BookRobDto;
import com.zheng.redpacket.server.serivce.BookRobService;
import org.apache.curator.framework.CuratorFramework;
import org.apache.curator.framework.recipes.locks.InterProcessMutex;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.awt.print.Book;
import java.util.Date;
import java.util.concurrent.TimeUnit;

@Service
public class BookRobImpl implements BookRobService {
    private static final Logger LOGGER = LoggerFactory.getLogger(BookRobImpl.class);
    private static final String pathPrefix = "/book/zkLock";

    @Autowired
    BookRobMapper bookRobMapper;
    @Autowired
    BookStockMapper bookStockMapper;
    @Autowired
    CuratorFramework client;
    @Autowired
    RedissonClient redisson;

    /**
     * 书籍抢购，不加分布式锁
     * @param dto
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void robWithNoLock(BookRobDto dto) throws Exception {
        dealRobBook(dto);
    }

    /**
     * 书籍抢购，不加分布式锁
     * @param dto
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void robWithLock(BookRobDto dto) throws Exception {
        InterProcessMutex mutex = new InterProcessMutex(client, pathPrefix + dto.getBookNo() + dto.getUserId() + "-lock");
        try {
            if (mutex.acquire(15L, TimeUnit.SECONDS)) {
                dealRobBook(dto);
            } else {
                throw new RuntimeException("获取分布式锁失败");
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            //TODO:不管结果都要如何释放锁
            mutex.release();
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void robWithRedisson(BookRobDto dto) throws Exception {
        final String key = "redissonTryLock-" + dto.getBookNo()+"-lock";
        //获取分布式锁实例
        RLock lock = redisson.getLock(key);
        try {
            Boolean locked = lock.tryLock(100, 10, TimeUnit.SECONDS);
            if (locked) {
               dealRobBook(dto);
            } else {
                LOGGER.info("获取分布式锁失败");
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }

    private void dealRobBook(BookRobDto dto) throws Exception {
        //TODO:处理逻辑
        BookStock stock = bookStockMapper.selectByBookNo(dto.getBookNo());
        int total = bookRobMapper.countByBookNoUserId(dto.getUserId(), dto.getBookNo());
        if (stock != null && stock.getStock() > 0 && total <= 0) {
            synchronized (stock.getStock()) {
                LOGGER.info("------书籍抢购，加锁-------，当前信息：{}", dto);
                int res = bookStockMapper.updateStockWithLock(dto.getBookNo());
                if (res > 0) {
                    BookRob bookRob = new BookRob();
                    BeanUtils.copyProperties(dto, bookRob);
                    bookRob.setRobTime(new Date());
                    bookRobMapper.insertSelective(bookRob);
                    LOGGER.info("------当前线程抢到书籍---------", dto);
                }
                Thread.sleep(1000);
            }
        }else {
            LOGGER.info("库存不足");
        }
    }
}
